package net.pws.common.persistence.mapbean.service.impl;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.pws.common.persistence.EntityManager;
import net.pws.common.persistence.mapbean.model.MapBean;
import net.pws.common.persistence.mapbean.service.MapBeanService;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.util.Assert;


public class MapBeanServiceImpl implements MapBeanService, InitializingBean {
    
    private EntityManager entityManager;
    
    public MapBeanServiceImpl() {
        super();
    }
    
    public MapBeanServiceImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
    
    public EntityManager getEntityManager() {
        return entityManager;
    }
    
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
    
    public void saveOrUpdate(MapBean mapBean) {
        if (StringUtils.isEmpty(mapBean.getId())) {
            mapBean.insert(entityManager);
        }
        else {
            mapBean.update(entityManager);
        }
    }
    
    public void save(MapBean mapBean) {
        mapBean.insert(entityManager);
    }
    
    public void update(MapBean mapBean) {
        mapBean.update(entityManager);
    }
    
    public void remove(MapBean mapBean) {
        mapBean.remove(entityManager);
    }
    
    public void saveOrUpdate(MapBean[] mapBeans) {
        for (int i = 0; i < mapBeans.length; i++) {
            saveOrUpdate(mapBeans[i]);
        }
    }
    
    public void save(MapBean[] mapBeans) {
        for (int i = 0; i < mapBeans.length; i++) {
            save(mapBeans[i]);
        }
    }
    
    public void update(MapBean[] mapBeans) {
        for (int i = 0; i < mapBeans.length; i++) {
            update(mapBeans[i]);
        }
    }
    
    public void remove(MapBean[] mapBeans) {
        for (int i = 0; i < mapBeans.length; i++) {
            remove(mapBeans[i]);
        }
    }
    
    public List<MapBean> find(String queryStatement) {
        return find(queryStatement, new Object[] {});
    }
    
    public List<MapBean> find(String queryStatement, Object parameter) {
        return find(queryStatement, new Object[] { parameter });
    }
    
    public List<MapBean> find(String queryStatement, Object[] parameters) {
        return entityManager.nativeFindList(queryStatement,
                                            parameters,
                                            new RowMapper() {
                                                
                                                public Object mapRow(ResultSet rs,
                                                                     int rowNum) throws SQLException {
                                                    MapBean result = new MapBean();
                                                    result.setId(rs.getString(MapBean.DEFAULT_ID_COLUMN_NAME));
                                                    Map properties = new HashMap();
                                                    result.setProperties(properties);
                                                    
                                                    ResultSetMetaData resultMetadata = rs.getMetaData();
                                                    int columnCount = resultMetadata.getColumnCount();
                                                    for (int i = 1; i <= columnCount; i++) {
                                                        String columnName = resultMetadata.getColumnName(i);
                                                        if (MapBean.DEFAULT_ID_COLUMN_NAME.equals(columnName)) {
                                                            continue;
                                                        }
                                                        properties.put(columnName,
                                                                       rs.getString(columnName));
                                                    }
                                                    
                                                    return result;
                                                }
                                            });
    }
    
    public List<Map> findMap(String queryStatement) {
        return findMap(queryStatement, new Object[] {});
    }
    
    public List<Map> findMap(String queryStatement, Object parameter) {
        return findMap(queryStatement, new Object[] { parameter });
    }
    
    public List<Map> findMap(String queryStatement, Object[] parameters) {
        return entityManager.nativeFindList(queryStatement,
                                            parameters,
                                            new RowMapper() {
                                                
                                                public Object mapRow(ResultSet rs,
                                                                     int rowNum) throws SQLException {
                                                    Map properties = new HashMap();
                                                    
                                                    ResultSetMetaData resultMetadata = rs.getMetaData();
                                                    int columnCount = resultMetadata.getColumnCount();
                                                    for (int i = 1; i <= columnCount; i++) {
                                                        String columnName = resultMetadata.getColumnName(i);
                                                        properties.put(columnName,
                                                                       rs.getString(columnName));
                                                    }
                                                    
                                                    return properties;
                                                }
                                            });
    }
    
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(entityManager);
    }
    
}
